package com.crcc.common.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.crcc.common.constant.CommonConsts;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author wangcl
 * @version 1.0
 * @description: 字符工具类
 * @date 2021/4/27 11:27
 */
public class StringUtil {

    public static String getRegStr(String sourceStr){
        String regEx="[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        Pattern p = Pattern.compile(regEx);
        Matcher m1 = p.matcher(sourceStr);
        if(m1.find()) {
            CharSequence cs = sourceStr;
            int j = 0;
            for (int i = 0; i < cs.length(); i++) {
                String temp = String.valueOf(cs.charAt(i));
                Matcher m2 = p.matcher(temp);
                if (m2.find()) {
                    StringBuilder sb = new StringBuilder(sourceStr);
                    sourceStr = sb.insert(j, "\\").toString();
                    j++;
                }
                j++; //转义完成后str的长度增1
            }
        }
        return sourceStr;
    }

    /**
     * 将 fastjson的JSONArray转化为泛型列表
     * @param jsonArray 源数据
     * @param clz 泛型类
     * @param <T> 泛型
     * @return list
     */
    public static <T> List<T> convertJSONArrayToTypeList(JSONArray jsonArray, Class<T> clz){
        if (CollectionUtils.isEmpty(jsonArray)){
            return new ArrayList<>();
        }
        List<T> result = new ArrayList<T>(jsonArray.size());
        jsonArray.forEach(element->{
            // 基础类型不可以转化为JSONObject，需要特殊处理
            if (element instanceof String
                    || element instanceof Number
                    || element instanceof Boolean
            ){
                result.add((T)element);
            }else {
                T t = JSONObject.toJavaObject((JSONObject)element, clz);
                result.add(t);
            }
        });
        return result;
    }

    /**
     * string时间字符串转long型
     * @param DateTime 日期
     * @return long型时间戳
     * @throws Exception
     */
    public static Long getDateToLong(String DateTime) throws Exception{
        if("0".equals(DateTime)){//证件有效期为长期
            return 0L;
        }else if(!StringUtils.isNotBlank(DateTime)||"".equals(DateTime)){
            return null;
        }else{
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            Date time = sdf.parse(DateTime);
            return time.getTime();
        }
    }

    //身份证前三后四脱敏
    public static String idEncrypt(String id) {
        if (StringUtils.isBlank(id) || (id.length() < 8)) {
            return id;
        }
        return id.replaceAll("(?<=\\w{10})\\w(?=\\w{3})", "*");
    }
    /**
     * 解析地址
     * @param address
     * @return
     */
    public static List<Map<String,String>> addressResolution(String address){
        /*
         * java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包。它包括两个类：Pattern和Matcher Pattern
         *    一个Pattern是一个正则表达式经编译后的表现模式。 Matcher
         *    一个Matcher对象是一个状态机器，它依据Pattern对象做为匹配模式对字符串展开匹配检查。
         *    首先一个Pattern实例订制了一个所用语法与PERL的类似的正则表达式经编译后的模式，然后一个Matcher实例在这个给定的Pattern实例的模式控制下进行字符串的匹配工作。
         */
        String regex="(?<province>[^省]+自治区|.*?省|.*?行政区|.*?市)(?<city>[^市]+自治州|.*?地区|.*?行政单位|.+盟|市辖区|.*?市)(?<county>[^县]+县|.+区|.+市|.+旗|.+海域|.+岛)?(?<town>[^区]+区|.+镇)?(?<village>.*)";
        Matcher m=Pattern.compile(regex).matcher(address);
        String province=null,city=null,county=null,town=null,village=null;
        List<Map<String,String>> table=new ArrayList<Map<String,String>>();
        Map<String,String> row=null;
        while(m.find()){
            row=new LinkedHashMap<String,String>();
            province=m.group("province");
            row.put("province", province==null?"":province.trim());
            city=m.group("city");
            row.put("city", city==null?"":city.trim());
            table.add(row);
        }
        return table;
    }

    /**
     * 生成6位随机数
     * @return
     */
    public static String randomCode() {
        StringBuilder str = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            str.append(random.nextInt(10));
        }
        return str.toString();
    }

    /**
     * 计算总综合评分：不满0.5为0.5,满0.5为1
     * @param divisor 除数
     * @param dividend 被除数
     * @return
     */
    public static float getLaborTotal(float divisor,int dividend){
        if (CommonConsts.ZERO == divisor){
            //入参为0
            return 0;
        }else {
            int tem = (int)(divisor/dividend);
            if (0 == tem){
                return 0;
            }else {
                float yu = divisor%dividend;
                if (CommonConsts.ZERO != yu){
                    //有余数
                    if ((yu*2) > dividend){
                        return tem + 1;
                    }else {
                        return tem + 0.5f;
                    }
                }else {
                    //无余数
                    return tem;
                }
            }
        }
    }

    public static String listToString(List list, char separator) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < list.size(); i++) {
            sb.append(list.get(i)).append(separator);
        }
        return list.isEmpty() ? "" : sb.substring(0, sb.toString().length() - 1);
    }

    /**
     * ftp图片转base64
     * @param ftpIp ip
     * @param ftpPort port
     * @param ftpUserName 用户名
     * @param ftpPassword 密码
     * @param ftpImgUrl 图片目录url
     * @param imgName 图片名
     * @return
     */
    public static String ftpToBase64(String ftpIp,int ftpPort,String ftpUserName,String ftpPassword,String ftpImgUrl,String imgName){

        FTPClient ftpClient = new FTPClient();
        String base64Str = null;
        InputStream inputStream = null;
        try {
            ftpClient.connect(ftpIp,ftpPort);
            ftpClient.login(ftpUserName, ftpPassword);
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            //是否成功登录服务器
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
            }
            //设置主动模式，防止在Linux上，由于安全限制，可能某些端口没有开启，出现阻塞
            ftpClient.enterLocalPassiveMode();
            //跳转到指定目录
            boolean changeWorkingDirectory = ftpClient.changeWorkingDirectory(ftpImgUrl);
            if (changeWorkingDirectory){
                //遍历下载的目录
                FTPFile[] fs = ftpClient.listFiles();
                String fileName = null;
                for (FTPFile ff : fs){
                    fileName = ff.getName();
                    ByteArrayOutputStream bos = null;
                    if(imgName.equals(fileName)){
                        inputStream = ftpClient.retrieveFileStream(new String(fileName.getBytes("gbk"), StandardCharsets.ISO_8859_1));
                        if (null == inputStream) {
                            throw new FileNotFoundException(fileName);
                        }else {
                            bos = new ByteArrayOutputStream();
                            int length;
                            byte[] buf = new byte[2048];
                            while (-1 != (length = inputStream.read(buf, 0, buf.length))) {
                                bos.write(buf, 0, length);
                            }
                            ByteArrayInputStream fis = new ByteArrayInputStream(bos.toByteArray());
                            bos.flush();
                            bos.close();
                            byte[] buffer = new byte[fis.available()];
                            int offset = 0;
                            int numRead = 0;
                            while (offset < buffer.length && (numRead = fis.read(buffer, offset, buffer.length - offset)) >= 0) {
                                offset += numRead;
                            }
                            if (offset != buffer.length) {
                                throw new IOException("Could not completely read file!");
                            }
                            fis.close();
                            base64Str = "data:image/jpg;base64,"+cn.hutool.core.codec.Base64Encoder.encode(buffer);
                            inputStream.close();
                            ftpClient.completePendingCommand();
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(ftpClient.isConnected()){
                try{
                    ftpClient.disconnect();
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
        return base64Str;
    }
    /**
     * 获取汉字串拼音首字母，英文字符不变
     * @param chinese 汉字串
     * @return 汉语拼音首字母
     */
    public static String getFirstSpell(String chinese) {
        if(chinese.contains("·")) {
            chinese = chinese.replace("·", "");
        }
        StringBuffer pybf = new StringBuffer();
        char[] arr = chinese.toCharArray();
        HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
        defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] > 128) {
                try {
                    String[] temp = PinyinHelper.toHanyuPinyinStringArray(arr[i], defaultFormat);
                    if (temp != null) {
                        pybf.append(temp[0].charAt(0));
                    }
                } catch (BadHanyuPinyinOutputFormatCombination e) {
                    e.printStackTrace();
                }
            } else {
                pybf.append(arr[i]);
            }
        }
        String name =pybf.toString().replaceAll("\\W", "").trim();
        String str = name.substring(0,1);
        //首字母大写
        String strUpper = str.toUpperCase();
        StringBuffer strbf = new StringBuffer();
        strbf.append(strUpper);
        strbf.append(name, 1, chinese.length());
        return strbf.toString();
    }

    /**
     * 去除小数点后多余0
     * @param bigDecimal
     * @return
     */
    public static String stripBigDecimal(BigDecimal bigDecimal){
        BigDecimal noZeros = bigDecimal.stripTrailingZeros();
        return noZeros.toPlainString();
    }


    /**
     * 驼峰转下划线命名
     * @Author xmj
     * @Description 驼峰转下划线命名
     * @Date 17:49 2023/3/16
     * @param str
     * @Return java.lang.String
     */
    public static String toUnderScoreCase(String str)
    {
        if (str == null)
        {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        // 前置字符是否大写
        boolean preCharIsUpperCase = true;
        // 当前字符是否大写
        boolean curreCharIsUpperCase = true;
        // 下一字符是否大写
        boolean nexteCharIsUpperCase = true;
        for (int i = 0; i < str.length(); i++)
        {
            char c = str.charAt(i);
            if (i > 0)
            {
                preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
            }
            else
            {
                preCharIsUpperCase = false;
            }

            curreCharIsUpperCase = Character.isUpperCase(c);

            if (i < (str.length() - 1))
            {
                nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
            }

            if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
            {
                sb.append('_');
            }
            else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
            {
                sb.append('_');
            }
            sb.append(Character.toLowerCase(c));
        }

        return sb.toString();
    }


    /**
     * 驼峰式命名法 例如：user_name->userName
     * @Author xmj
     * @Description 驼峰式命名法 例如：user_name->userName
     * @Date 17:40 2023/3/16
     * @param s 传入参数
     * @Return java.lang.String
     */
    public static String toCamelCase(String s) {
        if (s == null)
        {
            return null;
        }
        s = s.toLowerCase();
        StringBuilder sb = new StringBuilder(s.length());
        boolean upperCase = false;
        for (int i = 0; i < s.length(); i++)
        {
            char c = s.charAt(i);

            if (c == '_')
            {
                upperCase = true;
            }
            else if (upperCase)
            {
                sb.append(Character.toUpperCase(c));
                upperCase = false;
            }
            else
            {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 处理富文本，去除富文本里各种标签
     * @param htmlStr 富文本字符串
     * @param strIndex 截取长度。当strIndex=-1时，不截取
     * @return
     */
    public static String dealHtml(String htmlStr,int strIndex){
        String str = htmlStr.replaceAll("<[.[^<]]*>","");
        if (strIndex != -1){
            if (str.length() > strIndex){
                str = str.substring(0,strIndex);
            }
        }

        return str;
    }

    /**
     * 去重
     * @Author xmj
     * @Description 去重
     * @Date 10:49 2023/7/13
     * @param keyExtractor
     * @Return java.util.function.Predicate<T>
     */
    public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
        Map<Object, Boolean> map = new ConcurrentHashMap<>();
        return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    public static void main(String[] args) throws Exception {

//       System.out.println( getFirstSpell("张晓芳"));
//        System.out.println(getRegStr("2342ad#$/?123"));
//        System.out.println(JSONArray.parseArray("[{}]").size());
//        System.out.println(getGeneralInfoTypeStr(1));
//        System.out.println(getLaborTotal(14.5f,4));
    }
}
